package cn.byzk.xframe.web.session;

import cn.byzk.xframe.web.common.constant.enums.CommonResponseEnum;
import cn.byzk.xframe.web.common.exception.BaseException;
import cn.byzk.xframe.web.common.exception.BusinessException;
import cn.byzk.xframe.web.session.model.SessionUser;
import cn.byzk.xframe.web.session.util.RequestHolder;
import cn.xcf.frame.encodings.EncodingUtil;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * SpringBoot 项目在项目启动类上添加 @EnableScheduling 注解即可开启定时任务管理。
 *
 * @author xcf
 * @date 2021/5/5 19:26
 */
@Service
@Slf4j
public class TokenMemory implements Token {

    private static final Map<String, List<Object>> map = new ConcurrentHashMap<>();

    private static final String SPLIT_1 = "::";


    private static final String TOKEN_KEY = "bk-token";
    private static final String TOKEN_KEY_2 = "bk-token2";
    private static final String TOKEN_KEY_3 = "bk-token3";


    @Value("${server.servlet.session.timeout}")
    private Duration timeOut;

    @Override
    public void init() {

    }




    @Override
    public String createToken(SessionUser sessionUser) {

        log.debug("创建Token开始,sessionUser={}", sessionUser.toString());
        StringBuilder src = new StringBuilder();
        src.append(sessionUser.getUserId()).append(SPLIT_1).append(sessionUser.getClientIp()).append(SPLIT_1).append(LocalDateTime.now());
        //String token = EncodingUtil.bytesToStrHex(SM3.create().digest(src.toString()));

        SHA256Digest sha256Digest = new SHA256Digest();
        sha256Digest.update(src.toString().getBytes(), 0, src.toString().getBytes().length);
        byte[] bEn = new byte[sha256Digest.getDigestSize()];
        sha256Digest.doFinal(bEn, 0);


        String token = EncodingUtil.bytesToStrHex(bEn);
        log.debug("创建Token完成,Token={}，sessionUser={}", token, sessionUser.toString());
        return token;
    }


    /**
     * sm3哈希
     * userId::clientIp制作token
     * @author xcf
     * @date 2021/5/5 14:51
     * @param sessionUser
     * @return java.lang.String
     */
    @Override
    public String create(SessionUser sessionUser) {

        String token = createToken(sessionUser);


//        Map<String,Object> infoMap = new HashMap<>();
//        sessionUser.getInfoMap().forEach((k,v)->{
//            infoMap.put(k,v);
//        });

        List<Object> list = new CopyOnWriteArrayList();
        LocalDateTime l1 = LocalDateTime.now().plusMinutes(timeOut.toMinutes());
        //list.add(sessionUser.getLastUpdateTime());
        list.add(l1);
        list.add(sessionUser.getUser());

        map.put(token, list);


        return token;
    }

    @Override
    public boolean auth(SessionUser sessionUser) {

        return false;
    }

    /**
     * 认证Token
     * @author xcf
     * @date 2021/5/5 17:43
     * @param token
     * @return boolean
     */
    @Override
    public boolean auth(String token) {
        log.debug("开始验证Token,session={}", token);


        if (!containServer(token)) {
            return false;
        }

        try {
            List<Object> list = map.get(token);
            //LocalDateTime l = (LocalDateTime) list.get(0);
            LocalDateTime now = LocalDateTime.now();
            //LocalDateTime l1 = l.plusMinutes(timeOut.toMinutes());
            LocalDateTime l1 = now.plusMinutes(timeOut.toMinutes());
            list.set(0, l1);
            map.put(token, list);
        } catch (Exception e) {
            log.error("验证Token失败,原因:{}", e.getMessage());
            CommonResponseEnum.AUTH_ERROR.assertFail();
            return false;
        }

        return true;
    }

    @Override
    public boolean verify(String token) {

        if (!containServer(token)) {
            return false;
        }

        return true;
    }

    @Override
    public void remove(String token) {
        if (0 != map.size()) {
            map.remove(token);
        }

    }


    @Override
    public Object getUser(String token) {

        if (0 == map.size()) {
            CommonResponseEnum.IS_NOT_LOGIN.assertFail();
        }

        return map.get(token).get(1);
    }


    /**
     * 与map进行对比
     * @author xcf
     * @date 2021/5/5 17:43
     * @param token
     * @return boolean
     */
    private boolean containServer(String token) {
        if (!map.containsKey(token)) {
            return false;
        }
        return true;
    }


    @Scheduled(cron = "0/1 * * * * ? ")
    public void clearExpiredToken() {
        LocalDateTime current = LocalDateTime.now();
        //StringBuilder logsb = new StringBuilder();

        try {
//            if (log.isDebugEnabled()) {
//                log.debug("------定时任务,检查Token过期状态,数量: {}", map.size());
//            }

            Iterator<String> it = map.keySet().iterator();
            while ( it.hasNext() ) {
                String key = it.next();
                List<Object> list = map.get(key);
                LocalDateTime time  = (LocalDateTime) list.get(0);
                //LocalDateTime expireTime = time.plusMinutes(timeOut.toMillis());
//                logsb.delete(0, logsb.length());
//                logsb.append(key).append(", 开始时间:").append(time).append(", 过期时间:").append(expireTime);
                if ( current.isAfter(time) ) {
                    it.remove();
                    //logsb.append(", 已过期，删除");
                }
//                if (log.isDebugEnabled()) {
//                    log.debug("------定时任务, {}", logsb.toString());
//                }

            }
        } finally {
        }
    }
}
